機器人小強一號的制作過程
從對機器人感興趣開始,買了一堆書,也看了很多資料,決定先從最簡單的車輪機器人開始做。普通電腦雖然強大,但是不能直接采集外界環境的物理數據,也不能直接控制電機。查找了下,雖然可以直接在電腦上接USB接口的數據采集器用于采集傳感器的數據,也可以使用PCI的電機控制卡來驅動各種電機,不過成本有些高,暫時不考慮了。找了一圈,發現還是單片機方案廉價,順便可以學習下單片機控制和作一些電路實驗。于是最終決定實驗方案采用單片機來做了。
零件
下面是采購的零件:
8位單片機Atmega168開發板。
電路面包板和連線用于驅動車輪的兩個減速電機。沒有找到合適的齒輪,自己也沒有加工設備,圖簡單,所以直接用集成減速齒輪的電機代替了。
距離傳感器,作為機器人的主要傳感器,用來探測障礙物的距離。使用的是常用的紅外距離傳感器作為機器人的眼睛。
舵機,用來控制機器人“眼睛”的方向。
下一步就可以驗證簡單的功能了。
實驗
接下來先搞清楚怎么用單片機。
Hello world
先讓單片機跑起來再說。習慣了操作系統下編程,第一次用單片機還真有些不習慣,擔心遇到問題,不過比較順利。這個程序用來點亮
單片機上的一個LED。
代碼:
int ledPin = 13; // LED connected to digital pin 13
<!--[if !supportEmptyParas]--> <!--[endif]-->
void setup()
{
pinMode(ledPin, OUTPUT); // sets the digital pin as output
}
<!--[if !supportEmptyParas]--> <!--[endif]-->
void loop()
{
digitalWrite(ledPin, HIGH); // sets the LED on
delay(1000); // waits for a second
digitalWrite(ledPin, LOW); // sets the LED off
delay(1000); // waits for a second
}
<!--[if !supportEmptyParas]--> <!--[endif]-->
以間隔1000ms的時間把單片機的第13 個Pin腳循環輸出高低電平,從而達到點亮和熄滅LED功能。很簡單,就是驗證下單片機是否可用。
控制舵機
舵機就是遙控模型上用來控制的,其實就是一個帶閉環控制的電機,能轉動到指定的角度。
工作原理是:控制信號由接收機的通道進入信號調制芯片,獲得直流偏置電壓。它內部有一個基準電路,產生周期為20ms,寬度為1.5ms的基準信號,將獲 得的直流偏置電壓與電位器的電壓比較,獲得電壓差輸出。
最后,電壓差的正負輸出到電機驅動芯片決定電機的正反轉。當電機轉速一定時,通過級聯減速齒輪帶動 電位器旋轉,使得電壓差為0,電機停止轉動。
在程序中控制舵機的轉動角度,就是生成不同脈寬的PWM就行了。
上面的代碼簡單的生成一個PWM 驅動舵機旋轉,比較簡單。 代碼中用delay來實現延時,如果是同時控制多個舵機,用這樣的代碼是不行的,需要自己計算時間。因為用delay整個單片機都“休息”了,無法執行任何代碼。在實際實現中,還需要不斷的讀取傳感器輸入和進行其他處理。
紅外距離傳感器
傳感器介紹:
SHARP紅外距離傳感器,用于模型或機器人制作,可以用來測量距離。每個模塊贈送一根15cm長PH2.0的單頭排線.
<!--[if !supportEmptyParas]--> <!--[endif]-->
技術規格:
<!--[if !supportEmptyParas]--> <!--[endif]-->
探測距離:10-80cm
工作電壓:4-5.5V
標準電流消耗:33-50 mA
輸出量:模擬量輸出,輸出電壓和探測距離成比例
接好電源,把模擬信號輸出端接在單片機的模擬輸入Pin就行了。
測試代碼:
int potPin = 2;
int ledPin = 13;
int val = 0;
<!--[if !supportEmptyParas]--> <!--[endif]-->
void setup() {
pinMode(ledPin, OUTPUT);
}
<!--[if !supportEmptyParas]--> <!--[endif]-->
void loop() {
val = analogRead(potPin);
digitalWrite(ledPin, HIGH);
delay(val);
digitalWrite(ledPin, LOW);
delay(val);
}
<!--[if !supportEmptyParas]--> <!--[endif]-->
運行結果,led隨著傳感器距離的變化閃爍間隔也隨著變化。
控制電機
常用的直流電機使用L293D來控制,使用H293的電路如下:
不過在驗證是發現,對于小電機,直接用單片機的PWM端子來輸出不同電壓的來控制速度也是可行的,雖然不太精確,但是對于實現運動特征是足夠了。單片機無法輸出真正的線性模擬電壓,PWM是通過調整空占比間隔來模擬不同電壓值的。
測量了電機在空載和負載情況下電流都只有幾十毫安,所以先采取這種簡單的辦法驗證。
直接把電機接到單片機的Gnd和 PWM Pin 9接口,然后在程序中直接向 Pin 9輸出就可以讓電機運轉了。
int value = 0;
int ledpin = 9;
<!--[if !supportEmptyParas]--> <!--[endif]-->
void setup()
{
// nothing for setup
}
<!--[if !supportEmptyParas]--> <!--[endif]-->
void loop()
{
for(value = 0 ; value <= 255; value+=5)
{
analogWrite(ledpin, value);
delay(30);
}
for(value = 255; value >=0; value-=5)
{
analogWrite(ledpin, value);
delay(30);
}
}
<!--[if !supportEmptyParas]--> <!--[endif]-->
上面的程序用不同的輸出值驅動電機,可以看到電機的旋轉效果。
<!--[if !supportEmptyParas]--> <!--[endif]-->
單片機和主要部件的驗證基本就完成了,下一步要開始程序設計了。
軟件設計
思路
在進行代碼編寫之前,想找到一種簡介的實現低級智能機器人的方式。目前的工業機器人采用的是精確控制的方法,在程序中固化每種處理邏輯。用程序員的思維來完成對機器人的操作。
對于程序員來說,機器人無非就是外接了物理傳感輸入和運動控制輸出的一臺電腦,不管是64位多核CPU或者8位單片機,只是性能的不同而已。理論上,都能通過程序設計來達到預定的目標。如果按照計算機上的普通程序來設計,那么大量的功能代碼會相互耦,每次為了增加一個新的運動功能或者任務,都需要編制新的代碼,而新的代碼給原來的環路反饋系統帶來新的邏輯分支,所有的步驟都得經過程序員的驗證和設計。這樣的設計對于精確計算的PC程序或者擅長固定場景精確動作的工業機器人來說,都沒有問題。但是對于這里要實現的“小強一號”機器人,是處在一個動態的變化環境當中,如果按照傳統的軟件設計邏輯,會存在大量耦合的邏輯分支,導致程序擴展性很差。舉例來說,為了完成一個沿墻壁行走的功能,必須對各種傳感器輸入情況進行判斷,然后做出預置的動作序列。
如果要執行的動作和需要判斷的情況很多,那么程序邏輯分支就比較復雜,擴展性也比較差,有沒有更好的適合機器人軟件設計的方法呢?
換一種思維來思考的話,我們要做的不是電腦程序,只是一個實驗機器人。這個實驗機器人能做到自然界昆蟲級的“智能”就很不錯了。 試想,一只螞蟻,一只蟑螂會去思考這么復雜的邏輯分支嗎?去考慮各種情況下應該采取的動作? 不太可能。我們用了復雜的想法去解決簡單的事情。
機器人和計算機的主要區別在于,計算機是按照預先規劃的指令運行,而機器人需要根據變化的環境選擇合適動作。我們首先可以簡化動作模型,我把機器人的執行任務分成3個層次:任務-》行為-》動作任務——機器人完成的一個期望目標,比如“在一個范圍內收集地面上的垃圾”可以界定為一個機器人的任務。
行為——行為是對任務的分解,行為是機器人根據環境變化選擇要做什么。比如碰到墻壁需要進行躲避。電源不足需要充電,就可以劃分為一個行為。
動作——機器人最終控制電機等輸出設備做出的動作,比如前進,后退,轉彎。轉動攝像頭都可以劃分成一個動作單元。
說明:任務由一系列的行為構成;行為有一個或者多個動作組成,動作是立即執行的最小單元。在任意一個時刻,只有一個動作可以得到執行。
軟件實現的對象就是分解出簡單的行為,針對每個行為單獨實現,互相之間無干涉、無耦合。當多個行為要輸出互相矛盾的動作時,通過一個行為優先級表來決定優先級高的行為來做出動作。在這個思路中,參考了基于行為編程的理論,關于詳細的基于行為編程的描述,可以在網上搜索“Behavior-based robotics”。
通過這種設計思路,可以實現對動物反射特性的模擬,不需要把精力放在復雜的邏輯處理上,只需要根據分解出的基本行為實現一個一個小的行為單元。每個行為單元只關心自己的傳感輸入和需要輸出的控制動作就行了。確定了設計思路,下一部分開始針對小強一號來設計軟件了。
參考資料,有興趣的可以閱讀:
http://www-robotics.usc.edu/~maja/publications/mitcs.ps.gz (這篇文章描述了如何分解行為,需要安裝 GSView)
http://www.research.ibm.com/people/j/jhc/pubs/jhc-design.pdf
http://www-robotics.usc.edu/~maja/bbs.html
《基于行為的機器人實戰指南》 中譯版
強一號結構非常簡單,傳感器只采用了個紅外距離傳感器作為機器人的“眼睛”,使用兩個電機進行運動,距離傳感器連接在一個舵機上,作為“頭部”可以左右范圍的轉動。機器人的行為最簡單的就是巡航行為,巡航行為就是給電機電流,電機轉動而已。那么發生碰撞怎么辦?在巡航行為中,不用考慮碰撞,否則又會變成復雜的判斷邏輯。為了避免碰撞,設計一個獨立的避免碰撞的“逃離”行為。逃離行為從距離傳感器獲取障礙物距離信息,簡單的判斷前方是否有障礙,進行避讓。由于多個行為都可能控制電機,所以需要一個仲裁器根據優先級來判斷到底執行那個邏輯部分輸出的控制指令。
下面用圖來說明這種情況:
如果需要增加其他更加復雜的智能,那么只需要增加對應的行為單元就行了,不用修改已有的邏輯結構。每個行為單元只需要處理自己關心的傳感器和需要控制的動作執行部分。這種方式的好處就是程序邏輯變得非常簡單,功能單元之間不會存在互相影響的弊端。
下面的代碼是“巡航”行為:
class BhCruis:public Behavior
{
public:
publicSPAN style="mso-tab-count: 2">
BhCruis(const char* name):Behavior(name){
};
BhCruis();
void Run();
void Setup();
};
void BhCruis::Setup(){
}
void BhCruis::Run(){
int bid = GetId();
GO_speed_left[bid] = 255;
GO_speed_right[bid] = 255;
GT_beh_action[ACTION_TYPE_MOTOR][bid] = true;
}
上面的代碼很簡單,就是讓兩個電機以同樣的速度暈裝,其他都不用考慮。對于某些行為,需要引入稍微復雜一些的處理,比如發現障礙物,首先要停下來,然后判斷是應該往左還是往右,做出決定之后,再進行具體的動作。針對這種不能在一個時刻完成,要經過幾個不同的狀態才能處理完成的行為,可以用狀態機來解決。下圖是“逃離”行為的狀態機:
對于行為實現自己的狀態機,在行為實現的代碼內部實現,而不影響其他行為。這種結構可以讓每個行為子關心自己的實現方式,從而最大的降低軟件復雜度,方便功能添加和修改。逃離行為狀態機實現原型代碼: void
void BhEscape::Run(){
int bid = GetId();
// 狀態機實現
switch(state){
case 0: // 前方距離過小
if(GI_distance[DISTANCE_FORWORD] < 30){
GO_speed_left[bid] = 0;
GO_speed_right[bid] = 0;
GT_beh_action[ACTION_TYPE_MOTOR][bid] = true;
timestart = millis();
state++; // 狀態變化
}else{
GT_beh_action[ACTION_TYPE_MOTOR][bid] = false;
}
break;
case 1SPAN style="mso-spacerun: yes"> // 觀察左右距離
if(millis() - timestart > 1000){
GO_eyeAngle[bid] = 0;
GT_beh_action[ACTION_TYPE_HEAD][bid] = true;
timestart = millis();
state++;
}
case 2SPAN style="mso-spacerun: yes"> // 觀察左右距離
if(millis() - timestart > 1000){
GO_eyeAngle[bid] = 180;
GT_beh_action[ACTION_TYPE_HEAD][bid] = true;
timestart = millis();
state++;
}
case 3SPAN style="mso-spacerun: yes"> // 決定往哪邊轉彎
if(millis() - timestart > 1000){
GO_eyeAngle[bid] = Angle_Center_90;
GT_beh_action[ACTION_TYPE_HEAD][bid] = true;
if(GI_distance[DISTANCE_LEFT_1] > GI_distance[DISTANCE_RIGHT_1]){
// 左轉
GO_speed_left[bid] = 0;
GO_speed_right[bid] = 255;
}else{
//右轉
GO_speed_left[bid] = 255;
GO_speed_right[bid] = 0;
}
GT_beh_action[ACTION_TYPE_MOTOR][bid] = true;
state = 0;
Delay(2000);
}
default:
break;
}
}
這種基于行為單元的實現方法比較類似生物的反射行為,完整的代碼在下載專區進行下載。完成了基本的代碼,下一部分需要構建機器人的機構和測試了。
結構和測試 實驗機器人的結構就地取材,用了一個拼裝玩具小車的零件,如下圖:
為了安裝電機和傳感器,重新拼裝了下,變成這個樣子:
有了基本的結構,可以測試功能了,驗證功能是否正常。
功能測試完成,放到地上實際跑一下:
有點好玩,基本達到可以巡航和壁障的功能,不過功能太過于簡單,只能相當于一個玩具。

提交
自動化機床的故障排除技術淺析
安川焊接機器人編程
ABB機器人控制軟件RobotWare應用手冊SafeMove(英文)
ABB IRB7600 機器人維護信息
ABB IRC5P機器人培訓教材